using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//处理消除的模块
public class MatchResolver : FieldEngine.MonoResolver {
  private class TempMatchInfo {
    public int count;
    public bool hasCollected;
  }

  private const int GOAL_LIMIT = 3;

  private List<Vector2Int> m_cachedMatchPositions = new List<Vector2Int>();

  private TempMatchInfo[,] m_tempMatchBuffer;

  public override void Resolve(IResolveEngine<FieldModel>.ResolveContext resolveContext) {
    var field = resolveContext.Model;
    var grid = field.gridModel;
    var size = field.param.size;
    PrepareMatchCountBuffer(size);

    for (int y = 0; y < size.y; y++) {
      var curBall = FieldModel.BallModel.Empty;
      var matchCnt = 0;
      var src = new Vector2Int();
      var dest = new Vector2Int();
      for (int x = 0; x < size.x; x++) {
        OnEachBall(field, x, y, isEndOfRow: x == size.x - 1, ref curBall, ref matchCnt, ref src, ref dest);
      }
    }

    for (int x = 0; x < size.x; x++) {
      var curBall = FieldModel.BallModel.Empty;
      var matchCnt = 0;
      var src = new Vector2Int();
      var dest = new Vector2Int();
      for (int y = 0; y < size.y; y++) {
        OnEachBall(field, x, y, isEndOfRow: y == size.y - 1, ref curBall, ref matchCnt, ref src, ref dest);
      }
    }

    bool hasMatch = m_cachedMatchPositions.Count > 0;

    if (hasMatch) {
      //收集消除信息
      foreach (var pos in m_cachedMatchPositions) {
        var tempInfo = m_tempMatchBuffer[pos.x, pos.y];
        if (tempInfo != null && !tempInfo.hasCollected) {
          tempInfo.hasCollected = true;
          var matchInfo = new MatchInfo {
            ball = grid.GetBallModel(pos).info,
            matchCount = tempInfo.count,
            generation = field.matchResolveContext.generation
          };

          MatchEffectEntry.OnMatch(matchInfo);
        }
      }

      //从棋盘上除去球
      foreach (var pos in m_cachedMatchPositions) {
        grid.EraseBallModel(pos);
      }
      m_cachedMatchPositions.Clear();

      field.matchResolveContext.OnMatch();
      resolveContext.pushRegisteredHolder(FieldView.HOLDER_KEY);
    } else {
      field.matchResolveContext.OnSettle();
    }

  }

  private void OnEachBall(FieldModel field, int x, int y, bool isEndOfRow, ref FieldModel.BallModel pickedBall, ref int matchCnt, ref Vector2Int src, ref Vector2Int dest) {
    var grid = field.gridModel;
    var nextBall = grid.GetBallModel(x, y);

    bool diffBall = nextBall.info != pickedBall.info;

    if (!pickedBall.isEmpty && !diffBall) {
      dest = new Vector2Int(x, y);
      matchCnt++;
    }

    if (!pickedBall.isEmpty && (diffBall || isEndOfRow)) { //当前连续的球已经到头了
      if (matchCnt >= GOAL_LIMIT) {
        bool hasPreviousMatch = false;
        for (int i = src.x; i <= dest.x; i++) {
          for (int j = src.y; j <= dest.y; j++) {
            m_cachedMatchPositions.Add(new Vector2Int(i, j)); //保存要消除的位置

            //如果这几个位置已经发生过消除，将两次消除合二为一（十字、T字）
            if (!hasPreviousMatch && m_tempMatchBuffer[i, j] != null) {
              m_tempMatchBuffer[i, j].count += matchCnt;
              hasPreviousMatch = true;
            }
          }
        }

        //如果这几个位置没有发生过消除，则写入新的消除信息
        if (!hasPreviousMatch) {
          var tempMatch = new TempMatchInfo {
            count = matchCnt
          };
          for (int i = src.x; i <= dest.x; i++) {
            for (int j = src.y; j <= dest.y; j++) {
              m_tempMatchBuffer[i, j] = tempMatch;
            }
          }
        }
      }
    }

    //update picked ball must be the last step
    if (diffBall) {
      pickedBall = nextBall;
      if (pickedBall.isEmpty) {
        matchCnt = 0;
      } else {
        src = new Vector2Int(x, y);
        matchCnt = 1;
      }
    }
  }

  private void PrepareMatchCountBuffer(Vector2Int size) {
    if (m_tempMatchBuffer == null ||
        m_tempMatchBuffer.GetLength(0) != size.x ||
        m_tempMatchBuffer.GetLength(1) != size.y) {
      m_tempMatchBuffer = new TempMatchInfo[size.x, size.y];
    } else {
      for (int x = 0, xcount = m_tempMatchBuffer.GetLength(0); x < xcount; x++) {
        for (int y = 0, ycount = m_tempMatchBuffer.GetLength(1); y < ycount; y++) {
          m_tempMatchBuffer[x, y] = null;
        }
      }
    }
  }
}

//用来计算单次消除的信息，用来判断道具球的特殊触发类型
public struct MatchInfo {
  public BallInfo ball;
  public int matchCount;
  public int generation;
}